/*****************************************************************************
* File Name: ble.c
*
* Version: 1.0
*
* Description:
* This file contains API for sending HID reports over BLE
*
* Note:
* Defining DISABLE_BLE in platform.h to disable ble module
*
* Owner: MRAO
*
* Related Document:
* BLE Component data sheet
*
* Hardware Dependency:
* Antenna
*
* Code Tested With:
* 1. PSoC Creator 3.1 
* 2. ARM GCC 4.8.4
******************************************************************************
* Copyright (2015), Cypress Semiconductor Corporation.
******************************************************************************
* This software is owned by Cypress Semiconductor Corporation (Cypress) and is
* protected by and subject to worldwide patent protection (United States and
* foreign), United States copyright laws and international treaty provisions.
* Cypress hereby grants to licensee a personal, non-exclusive, non-transferable
* license to copy, use, modify, create derivative works of, and compile the
* Cypress Source Code and derivative works for the sole purpose of creating
* custom software in support of licensee product to be used only in conjunction
* with a Cypress integrated circuit as specified in the applicable agreement.
* Any reproduction, modification, translation, compilation, or representation of
* this software except as specified above is prohibited without the express
* written permission of Cypress.
*
* Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH
* REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
* Cypress reserves the right to make changes without further notice to the
* materials described herein. Cypress does not assume any liability arising out
* of the application or use of any product or circuit described herein. Cypress
* does not authorize its products for use as critical components in life-support
* systems where a malfunction or failure may reasonably be expected to result in
* significant injury to the user. The inclusion of Cypress' product in a life-
* support systems application implies that the manufacturer assumes all risk of
* such use and in doing so indemnifies Cypress against all charges. Use may be
* limited by and subject to the applicable Cypress software license agreement.
*****************************************************************************/
#include "ble.h"
#include "debug.h"

/* Macros for various service index */
#define HID_SERVICE_INDEX                               (CYBLE_HUMAN_INTERFACE_DEVICE_SERVICE_INDEX)
#define BATTERY_SERVICE_INDEX                           (CYBLE_BATTERY_SERVICE_SERVICE_INDEX)

#define BOOT_REPORT_MOUSE_SIZE                          (3u)            
#define BOOT_REPORT_KEYBOARD_SIZE                       (8u)

/* Starting register address where silicon ID for PRoC BLE is stored */
#define Get_Silicon_ID()                                (((uint8 *) CYREG_SFLASH_DIE_LOT0))   
#define SILICON_ID_SIZE                                 (12u)

#define TRIGGER_DISCONNECT                              (0x1)
#define TRIGGER_CONNECTION_UPDATE                       (0x2)
#define TRIGGER_AUTH_FAILED                             (0x4)
#define TRIGGER_ADD_TO_WHITELIST                        (0x8)

#ifndef DISABLE_BLE
    
bool disableLowPowerMode;
/* Variable to maintain the alert level for the link and immediate alert losses */
static uint8 llsAlertLevel,iasAlertLevel;

/* Variable to maintain link loss status */
static bool isLinkLossOccured = false;

#ifndef DISABLE_BLE_ENCYRPTION
static bool isAuthCompleted = false;
#endif /* DISABLE_BLE_ENCYRPTION */

#ifdef ENABLE_CONNECTION_UPDATE_REJECT_DISCONNECT
/* Variable to keep track of the low power mode */
static uint8 isLowPowerMode;
static uint8 rejectCounter;
#endif /* ENABLE_CONNECTION_UPDATE_REJECT_DISCONNECT */
static bool isDirectedAdvertisement = false, isScannableOnlyFromWhitelist = false;
/* variable to store the local peer bd address */
static CYBLE_GAP_BD_ADDR_T peerBdAddr;

/* Variable to detect the start and stop of BLE operations */
static uint8 prevBdHandle;
static bool isWritePeerAddr = false;
static uint8 bleAppTriggerEvent = 0;
static CYBLE_GAP_CONN_UPDATE_PARAM_T currentConnParam;

static Keyboard_Report   prevSendKeyboardReport;      /* Structure for storing the previously sent keyboard report */
static Power_Report      prevSendPowerReport;         /* Structure for storing the previously sent sending power report */
static Multimedia_Report prevSendMultimediaReport;    /* Structure for storing the previously sent sending multimedia report */   
static uint8 mouseButtonStatus;                       /* Variable for storing the previously sent mouse button status */

/*****************************************************************************
* Function Name: Ble_IsValidPeerAddressPresent()
******************************************************************************
* Summary:
* This function checks if the last connected peer address is valid or not
*
* Parameters:
* None
*
* Return:
* bool - True if the last connected peer address is valid
*
* Theory:
* Checks if the peer address value is not equal to zero
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
bool Ble_IsValidPeerAddressPresent(void)
{
    return (peerBdAddr.bdAddr[0] |  peerBdAddr.bdAddr[1] |  peerBdAddr.bdAddr[2] | \
                                   peerBdAddr.bdAddr[3] | peerBdAddr.bdAddr[4] | peerBdAddr.bdAddr[4]);
}

/*****************************************************************************
* Function Name: Ble_Update_Serial_Number_String()
******************************************************************************
* Summary:
* This function updates the serial number string in the device information service
* with the silicon id
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* Set the silicon ID for serial number parameter in the Device information service
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
static void Ble_Update_Serial_Number_String(void)
{
    const uint8 byteToAscillTable[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
    uint8 serialNumber[SILICON_ID_SIZE] = {0};
    uint8 i;
    uint8 *ptr = Get_Silicon_ID();

    for(i=0;i<SILICON_ID_SIZE;i+=2)
    {
        serialNumber[i] = byteToAscillTable[(*ptr >> 4) & 0xF];
        serialNumber[i+1] = byteToAscillTable[*ptr & 0xF];
        ptr++;
    }
    CyBle_DissSetCharacteristicValue(CYBLE_DIS_SERIAL_NUMBER, SILICON_ID_SIZE, serialNumber);
}

/*****************************************************************************
* Function Name: Ble_AppCallBack()
******************************************************************************
* Summary:
* This function is a callback for getting the GAP, GATT, L2CAP events from the 
* BLE component
*
* Parameters:
* event - Event from the BLE Component
* eventParam - Pointer to the event parameters 
*
* Return:
* None
*
* Theory:
* The callback function which will be used by teh BLE component to provide various
* events to the application
*
* Side Effects:
* 
* 
* Note:
* None
*****************************************************************************/
static void Ble_AppCallBack(uint32 event, void* eventParam)
{
    switch(event)
    {
        case CYBLE_EVT_L2CAP_CONN_PARAM_UPDATE_RSP:
#ifdef ENABLE_CONNECTION_UPDATE_REJECT_DISCONNECT
            if((*(uint16 *)eventParam))
            {
                rejectCounter++;
                if(isLowPowerMode && (rejectCounter => L2CAP_UPDATE_PARAMETER_REJECT_THRESHOLD))
                {
                    /*If L2CAP parameter update is rejected then disconnect the connection */                    
                    bleAppTriggerEvent |= TRIGGER_DISCONNECT;
                }
            }
            else
            {
                rejectCounter = 0;
            }
#endif /* ENABLE_CONNECTION_UPDATE_REJECT_DISCONNECT */
            break;
        /* GAP events */
        case CYBLE_EVT_GAP_DEVICE_CONNECTED:
            Debug_Print(DEBUG_MESSAGE_LEVEL_4,"CYBLE_EVT_GAP_DEVICE_CONNECTED\r\n");
            CyBle_GapGetPeerBdAddr(cyBle_connHandle.bdHandle, &peerBdAddr);            
            isWritePeerAddr = true;
            isLinkLossOccured = false;
            isDirectedAdvertisement = false;
            isScannableOnlyFromWhitelist = false;
            bleAppTriggerEvent |= TRIGGER_ADD_TO_WHITELIST;
            if(((CYBLE_GAP_CONN_PARAM_UPDATED_IN_CONTROLLER_T *)eventParam)->status == 0)
            {
                currentConnParam.connIntvMin = ((CYBLE_GAP_CONN_PARAM_UPDATED_IN_CONTROLLER_T *)eventParam)->connIntv;
                currentConnParam.connIntvMax = ((CYBLE_GAP_CONN_PARAM_UPDATED_IN_CONTROLLER_T *)eventParam)->connIntv;
                currentConnParam.connLatency = ((CYBLE_GAP_CONN_PARAM_UPDATED_IN_CONTROLLER_T *)eventParam)->connLatency;
                currentConnParam.supervisionTO = ((CYBLE_GAP_CONN_PARAM_UPDATED_IN_CONTROLLER_T *)eventParam)->supervisionTO;
            }
            /* Enable the following line if authentication request need to be sent from the remote control */
            /* CyBle_GapAuthReq(cyBle_connHandle.bdHandle, &cyBle_authInfo); */
            break;
        case CYBLE_EVT_GAP_DEVICE_DISCONNECTED:
            Debug_Print(DEBUG_MESSAGE_LEVEL_4,"CYBLE_EVT_GAP_DEVICE_DISCONNECTED\r\n");
            Debug_Print(DEBUG_MESSAGE_LEVEL_4,"reason of disconnect is = 0x%x\r\n",(*(uint8 *)eventParam));
            if(eventParam != NULL)
            {
                isLinkLossOccured = ((*(uint8 *)eventParam == BLE_LINK_TERMITATION_LINK_LOSS) || \
                                                    (*(uint8 *)eventParam == BLE_LINK_CONNECTION_TIMEOUT));
                memset(&prevSendKeyboardReport, 0, sizeof(Keyboard_Report));
                memset(&prevSendPowerReport, 0, sizeof(Power_Report));
                memset(&prevSendMultimediaReport, 0, sizeof(Multimedia_Report));
                mouseButtonStatus = 0;
                memset (cyBle_attValuesCCCD, 0, sizeof (cyBle_attValuesCCCD)); /* Reseting the CCCD Values */
#ifndef DISABLE_BLE_ENCYRPTION
                isAuthCompleted = false;
#endif /* DISABLE_BLE_ENCYRPTION */

#ifdef ENABLE_CONNECTION_UPDATE_REJECT_DISCONNECT
                rejectCounter = 0;
#endif /* ENABLE_CONNECTION_UPDATE_REJECT_DISCONNECT */
            }
            break;
        case CYBLE_EVT_GAP_CONNECTION_UPDATE_COMPLETE:
            if(((CYBLE_GAP_CONN_PARAM_UPDATED_IN_CONTROLLER_T *)eventParam)->status == 0)
            {
                currentConnParam.connIntvMin = ((CYBLE_GAP_CONN_PARAM_UPDATED_IN_CONTROLLER_T *)eventParam)->connIntv;
                currentConnParam.connIntvMax = ((CYBLE_GAP_CONN_PARAM_UPDATED_IN_CONTROLLER_T *)eventParam)->connIntv;
                currentConnParam.connLatency = ((CYBLE_GAP_CONN_PARAM_UPDATED_IN_CONTROLLER_T *)eventParam)->connLatency;
                currentConnParam.supervisionTO = ((CYBLE_GAP_CONN_PARAM_UPDATED_IN_CONTROLLER_T *)eventParam)->supervisionTO;
            }
            break;
        case CYBLE_EVT_GAP_AUTH_FAILED:
            /* Remove the Bond information if the AUTH failed */
            if((*(CYBLE_GAP_AUTH_FAILED_REASON_T *)eventParam == CYBLE_GAP_AUTH_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE) || 
                (*(CYBLE_GAP_AUTH_FAILED_REASON_T *)eventParam == CYBLE_GAP_AUTH_ERROR_CONFIRM_VALUE_NOT_MATCH))
            {
                prevBdHandle = cyBle_connHandle.bdHandle;
                /* Remove the Bond information if the AUTH failed */
                bleAppTriggerEvent |= (TRIGGER_DISCONNECT | TRIGGER_AUTH_FAILED | TRIGGER_ADD_TO_WHITELIST);
            }
            break;
        case CYBLE_EVT_GAP_AUTH_COMPLETE:
#ifndef DISABLE_BLE_ENCYRPTION
            isAuthCompleted = true;
#endif /* DISABLE_BLE_ENCYRPTION */
            bleAppTriggerEvent |= TRIGGER_CONNECTION_UPDATE;
            if(((CYBLE_GAP_AUTH_INFO_T *)eventParam)->bonding)
            {
                bleAppTriggerEvent &= ~TRIGGER_ADD_TO_WHITELIST;
            }
            break;       
        default:
            break;
    }
}

/*****************************************************************************
* Function Name: Ble_ProcessEvents()
******************************************************************************
* Summary:
* This function checks if any activity is pending from the stack as well from the 
* BLE module
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* Calls the CyBle_ProcessEvents and performs action depending on the trigger events
*
* Side Effects:
* bleAppTriggerEvent is updated
* 
* Note:
* None
*****************************************************************************/
void Ble_ProcessEvents(void)
{
    CyBle_ProcessEvents();
    if(bleAppTriggerEvent)
    {
        if(bleAppTriggerEvent & TRIGGER_DISCONNECT)
        {
            if(CyBle_GetState() == CYBLE_STATE_CONNECTED)
            {
                CyBle_GapDisconnect(cyBle_connHandle.bdHandle);
            }
            bleAppTriggerEvent &= ~TRIGGER_DISCONNECT;
        }
        if(bleAppTriggerEvent & TRIGGER_CONNECTION_UPDATE)
        {
            Ble_Set_State(Device_GetCurrent_State());
            bleAppTriggerEvent &= ~TRIGGER_CONNECTION_UPDATE;
        }
    }
}

/*****************************************************************************
* Function Name: Ble_BasCallBack()
******************************************************************************
* Summary:
* This function is a callback that is registered with Battery Service(BAS) for 
* getting the corresponding events from the BLE component 
*
* Parameters:
* event - Event from the BLE Component
* eventParam - Pointer to the event parameters 
*
* Return:
* None
*
* Theory:
* No events from the BAS service is used in the application
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
static void Ble_BasCallBack (uint32 event, void *eventParam)
{
    (void)eventParam; /* To Remove Compilation warnings */
    (void)event;
}

/*****************************************************************************
* Function Name: Ble_ScpsCallBack()
******************************************************************************
* Summary:
* This function is a callback that is registered with Scan Parameters Service(SPS) for 
* getting the corresponding events from the BLE component 
*
* Parameters:
* event - Event from the BLE Component
* eventParam - Pointer to the event parameters 
*
* Return:
* None
*
* Theory:
* No events from the SCPS service is used in the application
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
static void Ble_ScpsCallBack (uint32 event, void *eventParam)
{
   (void)eventParam; /* To Remove Compilation warnings */
   (void)event;
}

/*****************************************************************************
* Function Name: Ble_HidsCallBack()
******************************************************************************
* Summary:
* This function is a callback that is registered with HID Service(HIDS) for 
* getting the corresponding events from the BLE component 
*
* Parameters:
* event - Event from the BLE Component
* eventParam - Pointer to the event parameters 
*
* Return:
* None
*
* Theory:
* No events from the HIDS service is used in the application
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
static void Ble_HidsCallBack (uint32 event, void *eventParam)
{
    (void)eventParam; /* To Remove Compilation warnings */
    (void)event;
}

/*****************************************************************************
* Function Name: Ble_IasCallBack()
******************************************************************************
* Summary:
* This function is a callback that is registered with Immediate Alert Service(IAS) 
* for getting the corresponding events from the BLE component 
*
* Parameters:
* event - Event from the BLE Component
* eventParam - Pointer to the event parameters 
*
* Return:
* None
*
* Theory:
* iasAlertLevel is set in this function.
*
* Side Effects:
* iasAlertLevel is updated in this function
* 
* Note:
* None
*****************************************************************************/
static void Ble_IasCallBack(uint32 event, void *eventParam)
{
    if(event == CYBLE_EVT_IASS_WRITE_CHAR_CMD)
    {
       iasAlertLevel = ((CYBLE_IAS_CHAR_VALUE_T *)eventParam)->value->val[0];        
    }
}

/*****************************************************************************
* Function Name: Ble_LinkLossCallBack()
******************************************************************************
* Summary:
* This function is a callback that is registered with Link LossService(LLS) 
* for getting the corresponding events from the BLE component 
*
* Parameters:
* event - Event from the BLE Component
* eventParam - Pointer to the event parameters 
*
* Return:
* None
*
* Theory:
* iasAlertLevel is updated in this function
*
* Side Effects:
* llsAlertLevel is updated in this function
* 
* Note:
* None
*****************************************************************************/
static void Ble_LinkLossCallBack (uint32 event, void *eventParam)
{
    if(event == CYBLE_EVT_LLSS_WRITE_CHAR_REQ)
    {
        llsAlertLevel = ((CYBLE_LLS_CHAR_VALUE_T *)eventParam)->value->val[0];        
    }
}

/*****************************************************************************
* Function Name: Ble_TxPowerCallBack()
******************************************************************************
* Summary:
* This function is a callback that is registered with Tx Power Service(TPS) 
* for getting the corresponding events from the BLE component 
*
* Parameters:
* event - Event from the BLE Component
* eventParam - Pointer to the event parameters 
*
* Return:
* None
*
* Theory:
* No events from the Tx Power service is used in the application
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
static void Ble_TxPowerCallBack(uint32 event, void *eventParam)
{
    (void)event;
    (void)eventParam; /* To Remove Compilation warnings */
}

/*****************************************************************************
* Function Name: Ble_WriteBondedList()
******************************************************************************
* Summary:
* This function writes the Bond list into the flash
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* Calls the BLE component API for storing the CCCD values and keys into the 
* flash
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
void Ble_WriteBondedList(void)
{
#ifdef ENABLE_BONDING
    Watch_Dog_Timer_Clear();
    if(isWritePeerAddr)
    {
        isWritePeerAddr = false;
        Device_Flash_Write(&flashDataInRam.blePeerAddress, &peerBdAddr.bdAddr[0], sizeof(CYBLE_GAP_BD_ADDR_T));
    }

    if(cyBle_pendingFlashWrite)
    {
        Watch_Dog_Timer_Disable();
        CyBle_ExitLPM();
        CyBle_StoreBondingData(true);
        Watch_Dog_Timer_Enable();
    }
#endif /* ENABLE_BONDING */
}

/*****************************************************************************
* Function Name: Ble_Init()
******************************************************************************
* Summary:
* This function performs the required BLE initialization for various 
* profiles
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* Initilizes the BLE component and restores the peer address
*
* Side Effects:
* peerBdAddr and isLinkLossOccured variables are updated
* 
* Note:
* None
*****************************************************************************/
void Ble_Init(void)
{
#ifdef BLE_GET_STACK_VERSION
    CYBLE_STACK_LIB_VERSION_T stackVersion;
#endif /* BLE_GET_STACT_VERSION */

    CyBle_Start(Ble_AppCallBack);
    Ble_Update_Serial_Number_String();
    CyBle_BasRegisterAttrCallback(Ble_BasCallBack);
    CyBle_ScpsRegisterAttrCallback(Ble_ScpsCallBack);
    CyBle_HidsRegisterAttrCallback(Ble_HidsCallBack);
    CyBle_LlsRegisterAttrCallback(Ble_LinkLossCallBack);
    CyBle_IasRegisterAttrCallback(Ble_IasCallBack);
    CyBle_TpsRegisterAttrCallback(Ble_TxPowerCallBack);
#ifdef BLE_GET_STACK_VERSION
    CyBle_GetStackLibraryVersion(&stackVersion);
#endif /* BLE_GET_STACT_VERSION */
    Device_Flash_Restore(&peerBdAddr.bdAddr[0], &flashDataInRam.blePeerAddress,  sizeof(CYBLE_GAP_BD_ADDR_T));
    isLinkLossOccured = Ble_IsValidPeerAddressPresent();
}

/*****************************************************************************
* Function Name: Ble_WaitUntilStackFree()
******************************************************************************
* Summary:
* This function waits until the Stack is free
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* None
*
* Side Effects:
* None
* 
*****************************************************************************/
static void Ble_WaitUntilStackFree(void)
{
    while(CyBle_GattGetBusStatus() == CYBLE_STACK_STATE_BUSY)
    {
        Watch_Dog_Timer_Clear();
        CyBle_ProcessEvents();
        CySysPmSleep();
    }
}

/*****************************************************************************
* Function Name: Ble_Configure()
******************************************************************************
* Summary:
* This function configures the Clock configration of the BLESS and puts the BLESS
* into low power mode

* Parameters:
* None
*
* Return:
* None
*
* Theory:
* Set the Clock Configuration and Puts the BLESS into Low power mode 
*
* Side Effects:
* None
* 
* Note:
* This function should be called after Ble_Is_Init_Completed() return true
*****************************************************************************/
void Ble_Configure(void)
{
#ifdef ENABLE_BLESS_CLOCK_CONFIGURATION
    CYBLE_BLESS_CLK_CFG_PARAMS_T bleSsClockConfig = {BLE_CRYSTAL_PPM, BLE_ECO_DIVIDER, BLE_ECO_START_UP_TIME};
    CyBle_SetBleClockCfgParam(&bleSsClockConfig);
#endif /* ENABLE_BLESS_CLOCK_CONFIGURATION */

#ifdef ENABLE_BLE_LOW_POWER_MODE
    CyBle_EnterLPM(CYBLE_BLESS_DEEPSLEEP);
#endif /* ENABLE_BLE_LOW_POWER_MODE */
    /* To make sure the last connected device in the white list */
    if(Ble_IsValidPeerAddressPresent())
    {
        CyBle_GapAddDeviceToWhiteList(&peerBdAddr);
    }
}

/*****************************************************************************
* Function Name: Ble_Set_Address()
******************************************************************************
* Summary:
* This function set the public BLE BD address for the device 
*
* Parameters:
* uint8 *address - pointer to the ble address that need to be set. Pass NULL to
*                  set the silicon ID as Public BLE BD address
*
* Return:
* None
*
* Theory:
* Sets the BLE BD address for this device. 
*
* Side Effects:
* None
* 
* Note:
* address pointer should be at least 6 bytes
*****************************************************************************/
void Ble_Set_Address(uint8 *address)
{
    CYBLE_GAP_BD_ADDR_T    bdAddr;
    if(address == NULL)
    {
        address = Get_Silicon_ID();
    }
    bdAddr.bdAddr[0] = *address++;
    bdAddr.bdAddr[1] = *address++;
    bdAddr.bdAddr[2] = *address++;
    bdAddr.bdAddr[3] = *address++;
    bdAddr.bdAddr[4] = *address++;
    bdAddr.bdAddr[5] = *address;
    bdAddr.type = CYBLE_GAP_ADDR_TYPE_PUBLIC;
    CyBle_SetDeviceAddress(&bdAddr);
}

/*****************************************************************************
* Function Name: Ble_Create_Audio_Channel()
******************************************************************************
* Summary:
* This function is used to create an audio channel with the peer device
*
* Parameters:
* None
*
* Return:
* bool - return true if BLE connection is initiated by the BLE component
*
* Theory:
* Audio channel request will be sent over the HID profile as notification
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
bool Ble_Create_Audio_Channel(void)
{
    bool result = false;
    Audio_Control_Packet audioControlPacket;
    CYBLE_API_RESULT_T apiResult = CYBLE_ERROR_OK;
    if((CyBle_GetState() == CYBLE_STATE_CONNECTED) &&
        (CYBLE_IS_NOTIFICATION_ENABLED(cyBle_hidss[HID_SERVICE_INDEX].reportArray \
                                    [CYBLE_HUMAN_INTERFACE_DEVICE_REPORT_AUDIO_CONTROL - CYBLE_HIDS_REPORT].cccdHandle)) && 
        (CYBLE_IS_NOTIFICATION_ENABLED(cyBle_hidss[HID_SERVICE_INDEX].reportArray \
                                    [CYBLE_HUMAN_INTERFACE_DEVICE_REPORT_AUDIO_DATA - CYBLE_HIDS_REPORT].cccdHandle)
#ifndef DISABLE_BLE_ENCYRPTION
        && isAuthCompleted
#endif /* DISABLE_BLE_ENCYRPTION */
        )
    )
    {
        if(CyBle_HidssGetProtocolMode(HID_SERVICE_INDEX) != CYBLE_HIDS_PROTOCOL_MODE_BOOT)
        {
            audioControlPacket.controlDataLength = BLE_AUDIO_CHANNEL_COMMAND_LENGTH;
            audioControlPacket.controlCode = BLE_AUDIO_CHANNEL_COMMAND_OPCODE;
            audioControlPacket.controlData[0] = BLE_AUDIO_CHANNEL_CREATE_COMMAND;

            apiResult = CyBle_HidssSendNotification(cyBle_connHandle, HID_SERVICE_INDEX, \
                                            CYBLE_HUMAN_INTERFACE_DEVICE_REPORT_AUDIO_CONTROL, \
                                            audioControlPacket.controlDataLength, &audioControlPacket.controlCode);
        }
        result = (apiResult == CYBLE_ERROR_OK);
    }
    return result;
}

/*****************************************************************************
* Function Name: Ble_Disconnect_Audio_Channel()
******************************************************************************
* Summary:
* This function is used to disconnect the audio channel with the peer device 
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* Disconnects the audio channel by sending data over the HID profile
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
void Ble_Disconnect_Audio_Channel(void)
{
    Audio_Control_Packet audioControlPacket;
    if(CyBle_GetState() == CYBLE_STATE_CONNECTED)
    {
        if(CyBle_HidssGetProtocolMode(HID_SERVICE_INDEX) != CYBLE_HIDS_PROTOCOL_MODE_BOOT)
        {
            audioControlPacket.controlDataLength = BLE_AUDIO_CHANNEL_COMMAND_LENGTH;
            audioControlPacket.controlCode = BLE_AUDIO_CHANNEL_COMMAND_OPCODE;
            audioControlPacket.controlData[0] = BLE_AUDIO_CHANNEL_DISCONNECT_COMMAND;
            Ble_WaitUntilStackFree();
            CyBle_HidssSendNotification(cyBle_connHandle, HID_SERVICE_INDEX, CYBLE_HUMAN_INTERFACE_DEVICE_REPORT_AUDIO_CONTROL, \
                                                      audioControlPacket.controlDataLength, &audioControlPacket.controlCode);
        }
    }
}



/*****************************************************************************
* Function Name: Ble_Send_Battery_Data()
******************************************************************************
* Summary:
* This function is used to send battery status to the connected client
*
* Parameters:
* batteryLevel - Battery status expressed in percentage
*
* Return:
* bool - returns true if battery status is sent over BLE
*
* Theory:
* 
*
* Side Effects:
* 
* 
* Note:
* 
*****************************************************************************/
bool Ble_Send_Battery_Data(uint8 batteryLevel)
{
    bool result = false;
    if((CyBle_GetState() == CYBLE_STATE_CONNECTED) 
#ifndef DISABLE_BLE_ENCYRPTION
        && isAuthCompleted
#endif /* DISABLE_BLE_ENCYRPTION */
    )
    {
        /* Enable the below code if you need to send the battery data to the central side. Else 
         * data will be sent when the next time data is available 
         */
        
        /* Ble_WaitUntilStackFree(); */
        result =  (CyBle_BassSendNotification(cyBle_connHandle, BATTERY_SERVICE_INDEX, CYBLE_BAS_BATTERY_LEVEL, \
                                                        sizeof(batteryLevel), &batteryLevel) == CYBLE_ERROR_OK);
    }
    else
    {
        result = (CyBle_BassSetCharacteristicValue(BATTERY_SERVICE_INDEX, CYBLE_BAS_BATTERY_LEVEL,sizeof(batteryLevel), \
                                                                                        &batteryLevel) == CYBLE_ERROR_OK);
    }
    return result;
}

/*****************************************************************************
* Function Name: Ble_Send_Data()
******************************************************************************
* Summary:
* This function is used to sends report to the connected client
*
* Parameters:
* reportType - Type of the report that need to be sent
* report - Report data to be sent
*
* Return:
* bool - returns true if report is sent over BLE
*
* Theory:
* Sends the data into the corresponding Report Characteristics
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
bool Ble_Send_Data(ReportType reportType ,Report *report)
{   
    CYBLE_API_RESULT_T apiResult = CYBLE_ERROR_OK;
    uint8 protocol;
    uint8 i;
    if((CyBle_GetState() == CYBLE_STATE_CONNECTED)
#ifndef DISABLE_BLE_ENCYRPTION
        && isAuthCompleted
#endif /* DISABLE_BLE_ENCYRPTION */
    )
    {
        protocol = CyBle_HidssGetProtocolMode(HID_SERVICE_INDEX);
        if(reportType & KEYBOARD_REPORT)
        {
            /* Wait until the stack is free */
            Ble_WaitUntilStackFree();
            if(memcmp(&prevSendKeyboardReport, &report->keyboard_report, sizeof(Keyboard_Report)) != 0)
            {
                memcpy(&prevSendKeyboardReport, &report->keyboard_report, sizeof(Keyboard_Report));
                report->keyboard_report.keylength_used = 0;
                if(protocol == CYBLE_HIDS_PROTOCOL_MODE_BOOT)
                {
                    apiResult = CyBle_HidssSendNotification(cyBle_connHandle, HID_SERVICE_INDEX, \
                                CYBLE_HIDS_BOOT_KYBRD_IN_REP, BOOT_REPORT_KEYBOARD_SIZE, ((uint8 *)&report->keyboard_report.mkey));
                    Debug_Print(DEBUG_MESSAGE_LEVEL_4, "keybord send code=%d\r\n",report->keyboard_report.keycode[0]);
                }
                else
                {       
                    apiResult = CyBle_HidssSendNotification(cyBle_connHandle, HID_SERVICE_INDEX, \
                                                                CYBLE_HUMAN_INTERFACE_DEVICE_REPORT_KEYBOARD, \
                                                     (sizeof(Keyboard_Report)) , ((uint8 *)&report->keyboard_report.mkey));
                    Debug_Print(DEBUG_MESSAGE_LEVEL_4, "keybord send code=%d\r\n",report->keyboard_report.keycode[0]);
                }            
            }
        }
        
        if(reportType & MOUSE_REPORT)
        {
            Ble_WaitUntilStackFree();
            if(protocol == CYBLE_HIDS_PROTOCOL_MODE_BOOT)
            { 
                if((mouseButtonStatus != report->mouse_report.click) || (report->mouse_report.x != 0) || \
                                    (report->mouse_report.y != 0))
                {
                    mouseButtonStatus = report->mouse_report.click;
                    apiResult = CyBle_HidssSendNotification(cyBle_connHandle, HID_SERVICE_INDEX, \
                      CYBLE_HIDS_BOOT_MOUSE_IN_REP, BOOT_REPORT_MOUSE_SIZE, (uint8 *)(&(report->mouse_report.click)));
                }
            }
            else
            {
                if((mouseButtonStatus != report->mouse_report.click) || (report->mouse_report.x != 0) || \
                                    (report->mouse_report.y != 0) || (report->mouse_report.zwheel != 0) || \
                                                                                (report->mouse_report.hwheel != 0))
                
                {
                    mouseButtonStatus = report->mouse_report.click;
                    apiResult = CyBle_HidssSendNotification(cyBle_connHandle, HID_SERVICE_INDEX, CYBLE_HUMAN_INTERFACE_DEVICE_REPORT_MOUSE,\
                                             sizeof(Mouse_Report), ((uint8 *)&report->mouse_report.click));
                }
            }
            
        }
        if(reportType & MULTIMEDA_REPORT  && (protocol != CYBLE_HIDS_PROTOCOL_MODE_BOOT))
        {
            if(memcmp(&prevSendMultimediaReport, &report->multimedia_report, sizeof(Multimedia_Report)) != 0)
            {
                memcpy(&prevSendMultimediaReport, &report->multimedia_report, sizeof(Multimedia_Report));
                Ble_WaitUntilStackFree();
                apiResult = CyBle_HidssSendNotification(cyBle_connHandle, HID_SERVICE_INDEX, CYBLE_HUMAN_INTERFACE_DEVICE_REPORT_MULTIMEDIA, \
                                         (sizeof(Multimedia_Report)), ((uint8 *)&report->multimedia_report.multimedia_key_code));
            }
        }
        if((reportType & POWER_REPORT) && (protocol != CYBLE_HIDS_PROTOCOL_MODE_BOOT))
        {
            if(memcmp(&prevSendPowerReport, &report->power_report, sizeof(Power_Report)) != 0)
            {
                memcpy(&prevSendPowerReport, &report->power_report, sizeof(Power_Report));
                Ble_WaitUntilStackFree();
                apiResult = CyBle_HidssSendNotification(cyBle_connHandle, HID_SERVICE_INDEX, CYBLE_HUMAN_INTERFACE_DEVICE_REPORT_POWER, \
                                                  sizeof(Power_Report), ((uint8 *)&report->power_report.power_key_code));
            }
        }

        if((reportType & AUDIO_CONTROL_REPORT) && (report->audio_report.noOfAudioPacket == 0) && (protocol != CYBLE_HIDS_PROTOCOL_MODE_BOOT))
        {
            CyBle_HidssSendNotification(cyBle_connHandle, HID_SERVICE_INDEX, \
                                            CYBLE_HUMAN_INTERFACE_DEVICE_REPORT_AUDIO_CONTROL, \
                                                report->audio_control_packet.controlDataLength, \
                                                        &report->audio_control_packet.controlCode);    
        }

        if((reportType & AUDIO_REPORT) && (protocol != CYBLE_HIDS_PROTOCOL_MODE_BOOT))
        {
            for(i=0;i<report->audio_report.noOfAudioPacket;i++)
            {
                if(report->audio_report.audio_data[i] != NULL)
                {
                    Ble_WaitUntilStackFree();

                    if((reportType & AUDIO_CONTROL_REPORT) && (i == report->audio_control_packet.controlBufferPoint))
                    {
                        CyBle_HidssSendNotification(cyBle_connHandle, HID_SERVICE_INDEX, \
                                                    CYBLE_HUMAN_INTERFACE_DEVICE_REPORT_AUDIO_CONTROL, \
                                                        report->audio_control_packet.controlDataLength, \
                                                        &report->audio_control_packet.controlCode);    
                    }
                    apiResult = CyBle_HidssSendNotification(cyBle_connHandle, HID_SERVICE_INDEX, \
                                                                CYBLE_HUMAN_INTERFACE_DEVICE_REPORT_AUDIO_DATA, \
                                                                report->audio_report.audio_data[i]->audio_length, \
                                                            &report->audio_report.audio_data[i]->audio_buffer[0]);
                    CyBle_ProcessEvents();
                    if(apiResult != CYBLE_ERROR_OK)
                    {
                        if(apiResult == CYBLE_ERROR_MEMORY_ALLOCATION_FAILED)
                        {
                            i--;
                        }
                    }
                }
            }
        }
    }
    if(reportType & BATTERY_REPORT)
    {
        return Ble_Send_Battery_Data(report->battery_report.battery);
    }
    return (apiResult == CYBLE_ERROR_OK);
}

/*****************************************************************************
* Function Name: Ble_Force_StopAdvertisement()
******************************************************************************
* Summary:
* None
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* None
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
void Ble_Force_StopAdvertisement(void)
{
    if(CyBle_GetState() == BLE_STATE_ADVERTISING)
    {
        Ble_StopAdvertisement();
        while(CyBle_GetState() == CYBLE_STATE_ADVERTISING)
        {
            CyBle_ProcessEvents();
            CySysPmSleep();
        }
    }  
}   
/*****************************************************************************
* Function Name: Ble_StartAdvertisement()
******************************************************************************
* Summary:
* This function starts undirected\directed advertising over BLE to discover the
* client and connect to it
*
* Parameters:
* None
*
* Return:
* uint8 - returns status of the Advertisement
* Codes                                      Description
* ------                                     -------------
* BLE_ADVERTISE_STARTED                     - ADV has be started due this API call
* BLE_ADVERTISE_ALREADY_STARTED             - ADV was already in progress due to eariler API call
* BLE_ADVERTISE_NOT_STARTED_CONNECTED_STATE - ADV cannot be stated as it is in connected state
* BLE_ADVERTISE_NOT_STARTED                 - ADV cannot be stated due to errors
*
* Theory:
* Starts the directed ADV if startedDirectedAdvertisement is true, else 
* starts undirected ADV 
*
* Side Effects:
* isDirectedAdvertisement and bleAppTriggerEvent is updated
* 
* Note:
* None
*****************************************************************************/
uint8 Ble_StartAdvertisement(bool startedDirectedAdvertisement, bool scannableOnlyFromWhitelist)
{
    uint8 result = BLE_ADVERTISE_STARTED;
    CYBLE_API_RESULT_T apiResult;
    CYBLE_GAP_BONDED_DEV_ADDR_LIST_T bondList;
    Watch_Dog_Timer_Clear();
    if(bleAppTriggerEvent & TRIGGER_AUTH_FAILED)
    {
        if(CyBle_GetState() != CYBLE_STATE_CONNECTED)
        {
            CyBle_GapRemoveDeviceFromWhiteList(&peerBdAddr);
            CyBle_StoreAppData(cyBle_attValuesCCCD, cyBle_attValuesCCCDFlashMemory[prevBdHandle], 
                                           CYBLE_GATT_DB_CCCD_COUNT, true);
            bleAppTriggerEvent &= ~TRIGGER_AUTH_FAILED;
        }
    }

    if(bleAppTriggerEvent & TRIGGER_ADD_TO_WHITELIST)
    {
        apiResult = CyBle_GapAddDeviceToWhiteList(&peerBdAddr);
        if(apiResult == CYBLE_ERROR_OK)
        {
            bleAppTriggerEvent &= ~TRIGGER_ADD_TO_WHITELIST;
        }
    }

    CyBle_GapGetBondedDevicesList(&bondList);
    if(bondList.count == CYBLE_GAP_MAX_BONDED_DEVICE)
    {
        CyBle_GapRemoveOldestDeviceFromBondedList();
    }

    if(!startedDirectedAdvertisement)
    {
        /* Stop directed advertisement and start again */
        if((CyBle_GetState() == BLE_STATE_ADVERTISING) && ((isDirectedAdvertisement) || \
                                (isScannableOnlyFromWhitelist && !scannableOnlyFromWhitelist)))
        {
            Ble_StopAdvertisement();
            while(CyBle_GetState() == CYBLE_STATE_ADVERTISING)
            {
                CyBle_ProcessEvents();
                CySysPmSleep();
            }
        }
        isDirectedAdvertisement = false;
        cyBle_discoveryModeInfo.advParam->advType = CYBLE_GAPP_CONNECTABLE_UNDIRECTED_ADV;
        isScannableOnlyFromWhitelist = scannableOnlyFromWhitelist;
        if(scannableOnlyFromWhitelist)
        {
            cyBle_discoveryModeInfo.advParam->advFilterPolicy = 0x3;
            cyBle_discoveryModeInfo.advTo = BLE_CONNECT_TO_ONLY_WHITE_LIST_TIMEOUT;
        }
        else
        {
            cyBle_discoveryModeInfo.advParam->advFilterPolicy = 0x0;
            cyBle_discoveryModeInfo.advTo = BLE_CONNECT_TO_ANY_TIMEOUT;
        }
    }
    else
    {
        if(!Ble_IsValidPeerAddressPresent())
        {
            return (CyBle_GetState() == BLE_STATE_ADVERTISING);
        }
        isDirectedAdvertisement = true;
        cyBle_discoveryModeInfo.advParam->advType = CYBLE_GAPP_CONNECTABLE_HIGH_DC_DIRECTED_ADV;
        memcpy(cyBle_discoveryModeInfo.advParam->directAddr, &peerBdAddr.bdAddr, CYBLE_GAP_BD_ADDR_SIZE);
    }
    apiResult = CyBle_GappStartAdvertisement(CYBLE_ADVERTISING_CUSTOM);
    CyBle_ProcessEvents();
    if(CyBle_GetState() == BLE_STATE_ADVERTISING)
    {
        if(apiResult == CYBLE_ERROR_OK)
        {
            result =  BLE_ADVERTISE_STARTED;
            Debug_Print(DEBUG_MESSAGE_LEVEL_4,"BLE_ADVERTISE_STARTED\r\n");
        }
        else
        {
            result =  BLE_ADVERTISE_ALREADY_STARTED;
            Debug_Print(DEBUG_MESSAGE_LEVEL_4,"BLE_ADVERTISE_ALREADY_STARTED\r\n");
        }
    }
    else if(CyBle_GetState() == CYBLE_STATE_CONNECTED)
    {
        result =  BLE_ADVERTISE_NOT_STARTED_CONNECTED_STATE;
        Debug_Print(DEBUG_MESSAGE_LEVEL_4,"BLE_CONNECTED_STATE\r\n");
    }
    else
    {
        result =  BLE_ADVERTISE_NOT_STARTED;
        Debug_Print(DEBUG_MESSAGE_LEVEL_4,"BLE_ADVERTISE_NOT_STARTED\r\n");
    }
    return result;
}

/*****************************************************************************
* Function Name: Ble_StopAdvertisement()
******************************************************************************
* Summary:
* This function stops advertising
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* Stops the ongoing the advertisement
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
void Ble_StopAdvertisement(void)
{ 
    CyBle_GappStopAdvertisement();
}

/*****************************************************************************
* Function Name: Ble_Get_State()
******************************************************************************
* Summary:
* This function returns the current state of BLE 
*
* Parameters:
* None
*
* Return:
* uint8 - state of the BLE
*
* Theory:
* Gets the state of the BLE module depending upon the components' state 
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
uint8 Ble_Get_State(void)
{
    uint8 bleState = CyBle_GetState();
    if(CyBle_GetState() == CYBLE_STATE_CONNECTED)
    {
        if(iasAlertLevel == CYBLE_HIGH_ALERT)
        {
            bleState = BLE_STATE_CONNECTED_PATH_LOSS;
        }
    }
    else if((CyBle_GetState() == CYBLE_STATE_DISCONNECTED) || (CyBle_GetState() == BLE_STATE_ADVERTISING))
    {
        if(isLinkLossOccured || (llsAlertLevel != CYBLE_NO_ALERT))
        {
            bleState = BLE_STATE_DISCONNECTED_LINK_LOSS;
        }
    }
    return bleState;
}

/*****************************************************************************
* Function Name: Ble_Set_State()
******************************************************************************
* Summary:
* This function sets the device state to the BLE module
*
* Parameters:
* state - state of the device
*
* Return:
* None
*
* Theory:
* Set the state for the BLE module 
*
* Side Effects:
* isLinkLossOccured and isLowPowerMode is updated
* 
* Note:
* None
*****************************************************************************/
void Ble_Set_State(Device_State state)
{
    CYBLE_GAP_CONN_UPDATE_PARAM_T connParam;
    if(CyBle_GetState() == CYBLE_STATE_CONNECTED)
    {
        if(state == DEVICE_ACTIVE)
        {
#ifdef ENABLE_CONNECTION_UPDATE_REJECT_DISCONNECT
            isLowPowerMode = false;
#endif /* ENABLE_CONNECTION_UPDATE_REJECT_DISCONNECT */
            if(currentConnParam.connIntvMin != BLE_ACTIVE_CONNECTION_INTERVAL)
            {
                connParam.connLatency = BLE_ACTIVE_SLAVE_LATENCY;
                connParam.connIntvMin = BLE_ACTIVE_CONNECTION_INTERVAL;
                connParam.connIntvMax = BLE_ACTIVE_CONNECTION_INTERVAL;
                connParam.supervisionTO = BLE_ACTIVE_SUPERVISION_TIMEOUT;
                CyBle_L2capLeConnectionParamUpdateRequest(cyBle_connHandle.bdHandle, &connParam);
            }
        }
        else if(state == DEVICE_IDLE)
        {
#ifdef ENABLE_CONNECTION_UPDATE_REJECT_DISCONNECT
            isLowPowerMode = true;
#endif /* ENABLE_CONNECTION_UPDATE_REJECT_DISCONNECT */
            if((currentConnParam.connIntvMin != BLE_IDLE_CONNECTION_INTERVAL) || \
                                    (currentConnParam.connLatency <BLE_IDLE_SLAVE_LATENCY))
            {
                connParam.connLatency = BLE_IDLE_SLAVE_LATENCY;
                connParam.connIntvMin = BLE_IDLE_CONNECTION_INTERVAL;
                connParam.connIntvMax = BLE_IDLE_CONNECTION_INTERVAL;
                connParam.supervisionTO = BLE_IDLE_SUPERVISION_TIMEOUT;
                CyBle_L2capLeConnectionParamUpdateRequest(cyBle_connHandle.bdHandle, &connParam);
            }
        }
        else if(state == DEVICE_SLEEP)
        {
#ifdef ENABLE_CONNECTION_UPDATE_REJECT_DISCONNECT
            isLowPowerMode = true;
#endif /* ENABLE_CONNECTION_UPDATE_REJECT_DISCONNECT */
            if((currentConnParam.connIntvMin != BLE_SLEEP_CONNECTION_INTERVAL) || \
                                    (currentConnParam.connLatency < BLE_SLEEP_SLAVE_LATENCY))
            {
                connParam.connLatency = BLE_SLEEP_SLAVE_LATENCY;
                connParam.connIntvMin = BLE_SLEEP_CONNECTION_INTERVAL;
                connParam.connIntvMax = BLE_SLEEP_CONNECTION_INTERVAL;
                connParam.supervisionTO = BLE_SLEEP_SUPERVISION_TIMEOUT;
                CyBle_L2capLeConnectionParamUpdateRequest(cyBle_connHandle.bdHandle, &connParam);
            }
        }
#ifdef ENABLE_SYSTEM_DEEP_SLEEP
        else if(state == DEVICE_DEEP_SLEEP)
        {
            CyBle_GapDisconnect(cyBle_connHandle.bdHandle);
            isLinkLossOccured = true;
            return;
        }
#endif /* ENABLE_SYSTEM_DEEP_SLEEP */
    }
    else if(CyBle_GetState() == BLE_STATE_DISCONNECTED)
    {
#ifdef ENABLE_BLE_LOW_POWER_MODE
        CyBle_EnterLPM(CYBLE_BLESS_DEEPSLEEP);
#endif /* ENABLE_BLE_LOW_POWER_MODE */
    }
}

/*****************************************************************************
* Function Name: Ble_Stop()
******************************************************************************
* Summary:
* This function stops the BLE module
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* Disconnects the peer device if connected and stops the BLE component
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
void Ble_Stop(void)
{
    if(CyBle_GetState() == CYBLE_STATE_CONNECTED)
    {
        CyBle_GapDisconnect(cyBle_connHandle.bdHandle);
    }
    else if(CyBle_GetState() == CYBLE_STATE_ADVERTISING)
    {
        CyBle_GappStopAdvertisement();
    }

    if((CyBle_GetState() == CYBLE_STATE_CONNECTED) || (CyBle_GetState() == CYBLE_STATE_ADVERTISING)) 
    {
        /* Wait until the device gets to disconnected state */
        while((CyBle_GetState() != CYBLE_STATE_DISCONNECTED))
        {
            CyBle_ProcessEvents();
        }
    }
#ifdef ENABLE_BONDING
    Ble_WriteBondedList();
#endif /* ENABLE_BONDING */
    CyBle_Stop();
}

/*****************************************************************************
* Function Name: Ble_Enter_LowPowerMode()
******************************************************************************
* Summary:
* This function instructs the BLESS to enter deep sleep mode
*
* Parameters:
* None
*
* Return:
* bool - true if the BLESS enters deep sleep mode
*
* Theory:
* None
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
bool Ble_Enter_LowPowerMode(void)
{
    bool result = !disableLowPowerMode;
#ifdef ENABLE_BLE_LOW_POWER_MODE
    CYBLE_BLESS_STATE_T state = CyBle_GetBleSsState();
#endif /* ENABLE_BLE_LOW_POWER_MODE */

#ifdef ENABLE_BLE_LOW_POWER_MODE
        if(!disableLowPowerMode && (state != CYBLE_BLESS_STATE_DEEPSLEEP) && (state != CYBLE_BLESS_STATE_HIBERNATE))
        {
            CyBle_ProcessEvents();
            result = (CyBle_EnterLPM(CYBLE_BLESS_DEEPSLEEP) == CYBLE_BLESS_DEEPSLEEP);            
        }
#else
        result = false;
#endif /* ENABLE_BLE_LOW_POWER_MODE */
    return result;
}

#endif /* DISABLE_BLE */
